#include <tsin/runtime/BulletRuntime.hpp>

#include <tsin/library/BulletEvent.hpp>

#include <tsin/library/GameViewport.hpp>
#include <tsin/display/DecoratedImage.hpp>

#include <cstring>

#include <tsin/util/MemCheck.hpp>
using namespace tsin;

BulletRuntime::BulletRuntime()
        : stage(BULLET_STAGE_UTERO)
{
        memset(activeEvents, 0, MAX_ACTIVE_EVENTS * sizeof(BulletEvent *));
        memset(eventsPool, 0, MAX_EVENTS_IN_POOL * sizeof(BulletEvent *));
        nrActive = nrEvents = 0;
        image = 0;
}

BulletRuntime::~BulletRuntime()
{
        for (int i = 0; i < MAX_EVENTS_IN_POOL; i++)
                if (eventsPool[i] != 0)
                        eventsPool[i]->unref();
        if (image)
                delete image;
}

bool BulletRuntime::addBulletEvent(BulletEvent *event)
{
        if (nrActive == MAX_ACTIVE_EVENTS ||
            nrEvents == MAX_EVENTS_IN_POOL)
                return false;

        registerActiveEvent(event);

        for (int i = 0; i < MAX_EVENTS_IN_POOL; i++)
                if (eventsPool[i] == 0) {
                        eventsPool[i] = event;
                        nrEvents ++;
                        break;
                }

        return true;
}

bool BulletRuntime::registerActiveEvent(BulletEvent *event)
{
        if (nrActive == MAX_ACTIVE_EVENTS)
                return false;
        for (int i = 0; i < MAX_ACTIVE_EVENTS; i++)
                if (activeEvents[i] == 0) {
                        activeEvents[i] = event;
                        nrActive ++;
                        break;
                }
        return true;
}

BulletEvent **BulletRuntime::allocEventList(int size)
{
        if (nrEvents + size > MAX_EVENTS_IN_POOL)
                return 0;
        for (int i = 0; i < MAX_EVENTS_IN_POOL; i++) {
                if (eventsPool[i] != 0)
                        continue;
                int j;
                for (j = 1; j < size; j++)
                        if (eventsPool[i + j] != 0) {
                                i += j;
                                break;
                        }
                if (j == size)
                        return eventsPool + i;
        }

        return 0;
}

void BulletRuntime::checkEvents()
{
        for (int i = 0, n = 0; i < MAX_ACTIVE_EVENTS, n < nrActive; i++) {
                if (activeEvents[i] == 0)
                        continue;
                activeEvents[i]->postTick(0, this);
                (activeEvents[i] == 0) ? (nrActive --) : (n ++);
        }
}
